package com.ynet.middleground.approve.model;

import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.google.common.base.Throwables;
import com.ynet.core.common.PagerInfo;
import com.ynet.core.common.ServiceResult;
import com.ynet.core.exception.BusinessException;
import com.ynet.core.log.IfpLogger;
import com.ynet.core.util.IDUtil;
import com.ynet.middleground.approve.constant.WorkflowConstants;
import com.ynet.middleground.approve.utils.ErrorCodeUtil;
import com.ynet.middleground.user.bean.*;
import com.ynet.middleground.user.dto.*;
import com.ynet.middleground.user.service.*;

/**
 * @author liulx
 * @description 用户中心服务调用模块 <br />
 * @date 2019-11-26 15:02
 */
@Component
public class UserCenterModel {

    @Autowired
    private ErrorCodeUtil errorCodeUtil;

    @Reference(version = "0.0.1")
    private UserService userService;

    @Reference(version = "0.0.1")
    private RoleManagementService roleManagementService;

    @Reference(version = "0.0.1")
    private UserRoleRelationService userRoleRelationService;

    @Reference(version = "0.0.1")
    private BlackListManagementService blackListManagementService;

    @Reference(version = "0.0.1")
    private ChannelService channelService;

    @Reference(version = "0.0.1")
    private OrganizationManagementService organizationManagementService;

    /**
     * 更新用户状态，修改用户信息、用户认证场景下，会走审批流，审批结束后，会调用该服务
     *
     * @param userId 用户id
     * @param status 用户状态
     * @param channel 渠道
     * @param operationUserId 操作人id
     */
    public void updateUserState(String userId, String status, String channel, String operationUserId) {
        ChangeUserInfoReq changeUserInfoReq = new ChangeUserInfoReq();
        changeUserInfoReq.setUserId(getUserId(userId));
        changeUserInfoReq.setState(status);
        changeUserInfoReq.setTraceId(IDUtil.getSecureRandomId());
        changeUserInfoReq.setChannel(channel);
        changeUserInfoReq.setOperationUserId(getUserId(operationUserId));
        changeUserInfoReq.setRequestTime(new Date());
        ServiceResult<String> serviceResult;
        try {
            serviceResult = userService.changeUserInfo(changeUserInfoReq);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        getServiceResult(serviceResult);
    }

    /**
     * 修改用户信息，修改用户信息场景下，会走审批流，审批结束后，调用该服务
     * 
     * @param userId 用户id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @param changeUserInfoReq 用户信息修请求对象
     */
    public void updateUserInfo(String userId, String channel, String operationUserId,
        ChangeUserInfoReq changeUserInfoReq) {
        Optional.ofNullable(changeUserInfoReq)
            .orElseThrow(() -> new BusinessException("修改用户状态失败，修改用户信息对象为空", "ECAP0001"));

        /*// 调用用户中心查询用户 userAccounts
        List<UserInfoDto> userInfoDtos = queryUserInfo(userId, channel, operationUserId);
        if (userInfoDtos != null && !userInfoDtos.isEmpty()
            && userInfoDtos.get(0).getUserBaseInformationDto() != null) {
            String userAccounts = userInfoDtos.get(0).getUserBaseInformationDto().getUserAccounts();
            changeUserInfoReq.setUserAccounts(userAccounts);
        }*/
        changeUserInfoReq.setUserId(getUserId(userId));
        changeUserInfoReq.setTraceId(IDUtil.getSecureRandomId());
        changeUserInfoReq.setChannel(channel);
        changeUserInfoReq.setOperationUserId(getUserId(operationUserId));
        changeUserInfoReq.setRequestTime(new Date());
        ServiceResult<String> serviceResult;
        try {
            IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "流程调用修改用户信息服务,reqParams: {}",
                changeUserInfoReq.toString());
            serviceResult = userService.changeUserInfo(changeUserInfoReq);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        getServiceResult(serviceResult);
    }

    /**
     * 查询用户,修改用户信息场景下，会走审批流，审批结束后，调用该服务，然后再调用修改用户信息服务
     * 
     * @param userId 用户id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @return 查询用户信息
     */
    public List<UserInfoDto> queryUserInfo(String userId, String channel, String operationUserId) {
        QueryUserInfoReq req = new QueryUserInfoReq();
        req.setUserId(getUserId(userId));
        req.setPagerInfo(new PagerInfo());
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setChannel(channel);
        req.setOperationUserId(Integer.valueOf(operationUserId));
        req.setRequestTime(new Date());
        ServiceResult<List<UserInfoDto>> serviceResult;
        try {
            IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "流程调用查询用户信息服务,reqParams: {}",
                req.toString());
            serviceResult = userService.queryUserInfo(req);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        return getServiceResult(serviceResult);
    }

    /**
     * 查询用户基本信息
     *
     * @param userId 用户id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @return 用户基本信息
     */
    public UserBaseInformationDto getUserBaseInfoFirst(String userId, String channel, String operationUserId) {
        UserBaseInformationDto base = null;
        List<UserInfoDto> userInfo = queryUserInfo(userId, channel, operationUserId);
        if (userInfo != null && !userInfo.isEmpty()) {
            base = userInfo.get(0).getUserBaseInformationDto();
            if (base == null) {
                throw new BusinessException("用户不存在", "ECAP0509");
            }
        } else {
            throw new BusinessException("用户不存在", "ECAP0509");
        }
        return base;
    }

    /**
     * 根据用户id查询用户所属部门、角色关系
     *
     * @param userId 用户Id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @return 关系列表
     */
    public List<OrganRoleRelationshipDto> listUserRelationByUserId(String userId, String channel,
        Integer operationUserId) {
        QueryOrganRoleRelationReq queryOrganRoleRelationReq = new QueryOrganRoleRelationReq();
        queryOrganRoleRelationReq.setUserId(getUserId(userId));
        queryOrganRoleRelationReq.setTraceId(IDUtil.getSecureRandomId());
        queryOrganRoleRelationReq.setChannel(channel);
        queryOrganRoleRelationReq.setOperationUserId(operationUserId);
        queryOrganRoleRelationReq.setRequestTime(new Date());
        ServiceResult<List<OrganRoleRelationshipDto>> serviceResult;
        try {
            serviceResult = roleManagementService.queryOrganRoleRelationshipNoPage(queryOrganRoleRelationReq);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "根据用户id查询用户所属部门、角色关系异常,case:{}",
                Throwables.getStackTraceAsString(e));
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        return getServiceResult(serviceResult);
    }

    /**
     * 根据用户id查询企业用户所属企业角色关系
     *
     * @param userId 用户ID
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @return 企业角色关系列表
     */
    public List<UserRoleRelationDto> listEnterpriseUserRoleRelation(String userId, String channel,
        Integer operationUserId) {
        QueryUserRoleRelationListReq queryUserRoleRelationReq = new QueryUserRoleRelationListReq();
        queryUserRoleRelationReq.setUserId(getUserId(userId));
        queryUserRoleRelationReq.setTraceId(IDUtil.getSecureRandomId());
        queryUserRoleRelationReq.setChannel(channel);
        queryUserRoleRelationReq.setOperationUserId(operationUserId);
        queryUserRoleRelationReq.setRequestTime(new Date());
        ServiceResult<List<UserRoleRelationDto>> serviceResult;
        try {
            serviceResult = userRoleRelationService.queryUserRoleRelationInfo(queryUserRoleRelationReq);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "根据用户id查询企业用户所属企业角色关系,case:{}",
                Throwables.getStackTraceAsString(e));
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        return getServiceResult(serviceResult);
    }

    /**
     * 根据用户id查询用户所拥有的部门和部门角色集合 <br />
     *
     * @param userId 用户id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @param organId 机构id
     * @return 部门和部门角色总集合
     */
    public List<String> listUserGroupsByUserId(String userId, String channel, Integer operationUserId,
        Integer organId) {
        List<OrganRoleRelationshipDto> list = listUserRelationByUserId(userId, channel, operationUserId);
        if (organId != null) {
            // 过滤其他机构，只留取指定机构
            list = list.stream().filter(d -> d.getFirstOrganizational().equals(organId)).collect(Collectors.toList());
        }

        // 利用 TreeSet 的排序去重构造函数来达到去重元素的目的
        // 过滤重复的组织id
        ArrayList<OrganRoleRelationshipDto> groups = list.stream()
            .collect(Collectors.collectingAndThen(
                Collectors.toCollection(
                    () -> new TreeSet<>(Comparator.comparing(OrganRoleRelationshipDto::getOrganizationalId))),
                ArrayList::new));

        // 收集用户所拥有的部门id集合, 部门格式为 d:1001
        List<String> groupList =
            groups.stream().map(o -> WorkflowConstants.CANDIDATE_GROUP_DEPARTMENT_PREFIX + o.getOrganizationalId())
                .collect(Collectors.toList());

        // 利用 TreeSet 的排序去重构造函数来达到去重元素的目的
        // 根据 组织id-角色id 2个属性 去重复
        ArrayList<OrganRoleRelationshipDto> groupsRoles = list.stream()
            .collect(Collectors.collectingAndThen(
                Collectors.toCollection(
                    () -> new TreeSet<>(Comparator.comparing(o -> o.getOrganizationalId() + ";" + o.getRoleId()))),
                ArrayList::new));

        // 收集用户所拥有的 部门id、角色id 组合式 集合，部门格式为 dr:1001-1001
        List<String> groupRolesList = groupsRoles.stream()
            .map(o -> WorkflowConstants.CANDIDATE_GROUP_DEPARTMENT_ROLE_PREFIX + o.getOrganizationalId()
                + WorkflowConstants.CANDIDATE_GROUP_DEPARTMENT_ROLE_DELIMITER + o.getRoleId())
            .collect(Collectors.toList());

        // 合并部门、部门-角色集合
        groupList.addAll(groupRolesList);

        // 服务已经去重复
        List<UserRoleRelationDto> roleRelationList = listEnterpriseUserRoleRelation(userId, channel, operationUserId);
        List<String> enterpriseRolesList =
            roleRelationList.stream().map(o -> WorkflowConstants.CANDIDATE_GROUP_ENTERPRISE_ROLE_PREFIX + o.getRoleId())
                .collect(Collectors.toList());

        // 合并企业角色集合
        groupList.addAll(enterpriseRolesList);
        return groupList;
    }

    /**
     * 添加黑名单服务
     *
     * @param userId 用户id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @param reason 添加黑名单理由
     */
    public void addBlacklist(String userId, String channel, Integer operationUserId, String reason) {
        OperationBlacListReq req = new OperationBlacListReq();
        req.setUserId(getUserId(userId));
        req.setBlacklistReason(reason);
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setChannel(channel);
        req.setOperationUserId(operationUserId);
        req.setRequestTime(new Date());
        ServiceResult<String> serviceResult;
        try {
            serviceResult = blackListManagementService.addBlacList(req);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "添加黑名单服务,case:{}",
                Throwables.getStackTraceAsString(e));
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        getServiceResult(serviceResult);
    }

    /**
     * 移除黑名单服务
     *
     * @param userId 用户id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @param reason 移除黑名单理由
     */
    public void removeBlacklist(String userId, String channel, Integer operationUserId, String reason) {
        OperationBlacListReq req = new OperationBlacListReq();
        req.setUserId(getUserId(userId));
        req.setBlacklistReason(reason);
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setChannel(channel);
        req.setOperationUserId(operationUserId);
        req.setRequestTime(new Date());
        ServiceResult<String> serviceResult;
        try {
            serviceResult = blackListManagementService.removeBlacList(req);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(), "移除黑名单服务,case:{}",
                Throwables.getStackTraceAsString(e));
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        getServiceResult(serviceResult);
    }

    /**
     * 根据部门-角色关系查询用户列表
     * 
     * @param organizationalId 部门id
     * @param roleId 角色id
     * @param channel 渠道
     * @param operationUserId 操作人id
     * @return 企业角色关系列表
     */
    public List<Integer> listUserRelationByGroupId(String organizationalId, String roleId, String channel,
        Integer operationUserId) {
        QueryOrganRoleRelationReq queryOrganRoleRelationReq = new QueryOrganRoleRelationReq();
        queryOrganRoleRelationReq.setOrganizationalId(Integer.valueOf(organizationalId));
        queryOrganRoleRelationReq.setRoleId(Integer.valueOf(roleId));
        queryOrganRoleRelationReq.setTraceId(IDUtil.getSecureRandomId());
        queryOrganRoleRelationReq.setChannel(channel);
        queryOrganRoleRelationReq.setOperationUserId(operationUserId);
        queryOrganRoleRelationReq.setRequestTime(new Date());
        try {
            ServiceResult<List<OrganRoleRelationshipDto>> serviceResult =
                roleManagementService.queryOrganRoleRelationshipNoPage(queryOrganRoleRelationReq);
            List<OrganRoleRelationshipDto> result = getServiceResult(serviceResult);
            // 利用 TreeSet 的排序去重构造函数来达到去重元素的目的
            // 过滤重复的用户id
            ArrayList<OrganRoleRelationshipDto> groups = result.stream()
                .collect(Collectors.collectingAndThen(
                    Collectors
                        .toCollection(() -> new TreeSet<>(Comparator.comparing(OrganRoleRelationshipDto::getUserId))),
                    ArrayList::new));

            // 收集用户id
            return groups.stream().map(OrganRoleRelationshipDto::getUserId).collect(Collectors.toList());
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            IfpLogger.error(Thread.currentThread().getStackTrace()[1].getMethodName(),
                "根据组织id和角色id查询用户所属部门、角色关系异常,case:{}", Throwables.getStackTraceAsString(e));
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
    }

    /**
     * 获取 ServiceResult 结果值
     *
     * @param serviceResult 服务返回结果对象
     * @param <T> 返回对象数据中具体的数据类型
     * @return ServiceResult 结果值
     */
    private <T> T getServiceResult(ServiceResult<T> serviceResult) {
        Optional.ofNullable(serviceResult)
            .orElseThrow(() -> new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002"));
        if (serviceResult.isSuccess()) {
            return serviceResult.getResult();
        }
        throw new BusinessException(serviceResult.getErrorMsg(), serviceResult.getErrorCode());
    }

    /**
     * 转化用户ID格式
     * 
     * @param userId 字符串格式用户id
     * @return Integer 格式
     */
    public Integer getUserId(String userId) {
        if (StringUtils.isBlank(userId)) {
            throw new BusinessException("查询用户关联信息失败，用户ID不能为空", "00001");
        }
        Integer integer = null;
        try {
            integer = Integer.valueOf(userId);
        } catch (NumberFormatException e) {
            throw new BusinessException("用户ID格式只能为数字", "ECAP0003");
        }
        return integer;
    }

    /**
     * 根据渠道号查询渠道信息
     * 
     * @param operationUserId 操作人
     * @param channelCode 渠道号
     * @param channel 请求渠道
     * @return 渠道传输信息对象
     */
    public ChannelDTO queryChannelByCode(Integer operationUserId, String channelCode, String channel) {
        QueryChannelByCodeReq req = new QueryChannelByCodeReq();
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setOperationUserId(operationUserId);
        req.setRequestTime(new Date());
        req.setChannel(channel);
        req.setChannelCode(channelCode);
        ServiceResult<ChannelDTO> serviceResult;
        try {
            IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "流程调用查询渠道信息服务,reqParams: {}",
                req.toString());
            serviceResult = channelService.queryChannelByCode(req);
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        return getServiceResult(serviceResult);
    }

    /**
     * 调用用户中心"港内员工数据查询"服务
     * 
     * @param userId
     * @param channel
     * @return
     */
    public List<EmployeeInfoDto> queryEmployee(Integer userId, String channel) {
        // Step1: 准备查询条件
        QueryEmployeesInfoReq req = new QueryEmployeesInfoReq();
        req.setTraceId(IDUtil.getSecureRandomId());
        req.setOperationUserId(userId);
        req.setRequestTime(new Date());
        req.setChannel(channel);
        req.setUserId(userId);
        req.setPagerInfo(new PagerInfo());
        // Step2: 调用用户中心服务
        ServiceResult<List<EmployeeInfoDto>> serviceResult;
        List<EmployeeInfoDto> list = null;
        try {
            IfpLogger.info(Thread.currentThread().getStackTrace()[1].getMethodName(), "港内员工数据查询服务,reqParams: {}",
                req.toString());
            serviceResult = organizationManagementService.queryEmployee(req);
            if (serviceResult != null) {
                list = serviceResult.getResult();
            }
        } catch (BusinessException e) {
            throw new BusinessException(e.getMessage(), e.getCode());
        } catch (Exception e) {
            throw new BusinessException(errorCodeUtil.getValue("ECAP0002"), "ECAP0002");
        }
        return list;
    }

}
